/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pb138.XmlDataBase;

import com.sun.xml.ws.rx.util.SuspendedFiberStorage;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.exist.xmldb.EXistResource;
import org.w3c.dom.*;
import org.w3c.dom.stylesheets.MediaList;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.*;
import org.xmldb.api.base.Collection;
import org.xmldb.api.modules.XMLResource;
import org.xmldb.api.modules.XPathQueryService;

/**
 *
 * @author Viktor
 */
public class MediumManagerImpl implements MediumManager {

    private static String URI = "xmldb:exist://localhost:8899/exist/xmlrpc";
    private static final String driver = "org.exist.xmldb.DatabaseImpl";
    private static final String xsltPath = "http://localhost:8080/Videolib/tableTransform.xsl";
    private static final String xsltPathMovies = "http://localhost:8080/Videolib/moviesTransform.xsl";
    private String collectionName;
    private String admin;
    private String password;
    MovieManagerImpl movieManager;
    Database database;

    public MediumManagerImpl(String collectionName, String admin, String password) {
        try {

            movieManager = new MovieManagerImpl();
            this.collectionName = collectionName;
            this.admin = admin;
            this.password = password;
            System.err.println(admin + password);
            // initialise database driver

            Class cl = Class.forName(driver);
            database = (Database) cl.newInstance();
            database.setProperty("create-database", "true");
            DatabaseManager.registerDatabase(database);

        } catch (Exception ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void createMedium(Medium medium) throws DatabaseException, NullPointerException, IllegalArgumentException {

        String id;
        String resultXml = null;

        if (medium == null) {
            throw new NullPointerException();
        }
        if (medium.getId() != null) {
            throw new DatabaseException("Medium is in database already");
        }
        if (medium.getName() == null || medium.getType() == null) {
            throw new IllegalArgumentException("Invalid medium properties");
        }


        //---------------------------------------------------------------------------------------------------------//
        // initialise database collection => collection of XML files stored in URL path + collecion name
        Collection col = null;
        col = this.getCollection();
        if (col == null) {
            throw new NullPointerException("Collection");
        }
        //--------------------------------------------------------------------------------------------------------//
        // get Medium Id

        try {
            id = col.createId();
            medium.setId(id);
        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException("Can't create ID", ex);
        }


        // create DOC document
        Document doc = null;
        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            // medium
            doc = docBuilder.newDocument();
            Element medXml = doc.createElement("medium");
            doc.appendChild(medXml);

            // id
            Attr idXml = doc.createAttribute("id");
            idXml.setValue(medium.getId());
            medXml.setAttributeNode(idXml);

            // type
            medXml.setAttribute("type", medium.getType());

            // name element
            Element name = doc.createElement("name");
            name.setTextContent(medium.getName());
            medXml.appendChild(name);

            // movies
            Element moviesXml = doc.createElement("movies");

            // append movies to medium
            if (medium.getMovies() != null && !medium.getMovies().isEmpty()) {
                Iterator<Movie> iter = medium.getMovies().iterator();
                while (iter.hasNext()) {
                    Element movieXml = movieManager.createMovie(iter.next(), doc);
                    moviesXml.appendChild(movieXml);
                }
            }

            medXml.appendChild(moviesXml);

        } catch (ParserConfigurationException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }

        // store document to database
        XMLResource res = null;
        try {
            // create new XMLResource; an id will be assigned to the new resource       
            res = (XMLResource) col.createResource(medium.getId(), "XMLResource");
            res.setContentAsDOM(doc);
            col.storeResource(res);
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Document was successfully stored into database, document's ID: " + res.getId());


        } catch (Exception ex) {
            throw new DatabaseException("Error by storing document to database");
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
    }

    @Override
    public void deleteMedium(String id) throws IllegalArgumentException, NullPointerException, DatabaseException {
        // initialise database collection => collection of XML files stored in URL path + collecion name
        if (id == null) {
            throw new NullPointerException("id is null!");
        }

        Collection col = null;
        Resource res = null;
        try {
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }

            res = col.getResource(id);
            if (res == null) {
                throw new DatabaseException("Medium is not in database " + id);
            }
            col.removeResource(res);
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + id + " deleted!");

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException("DeleteMedium > Get collection failed :" + ex);
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }

    }

    @Override
    public void updateMedium(Medium medium) throws IllegalArgumentException, NullPointerException, DatabaseException {

        if (medium == null) {
            throw new NullPointerException();
        }
        if (medium.getId() == null) {
            throw new DatabaseException("Medium is not in database already");
        }
        if (medium.getName() == null || medium.getType() == null) {
            throw new IllegalArgumentException("Invalid medium properties");
        }

        String resultXml = null;
        Collection col = null;
        XMLResource res = null;
        Document doc;

        try {
            // Get collection
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }
            // Get resource
            res = (XMLResource) col.getResource(medium.getId());
            if (res == null) {
                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + medium.getId() + " not found !!!");
                throw new DatabaseException("updateMedium > Get resource with id failed :" + medium.getId());
            }
            // Get DOM
            doc = (Document) res.getContentAsDOM();

            // update Type and name
            Element medElem = (Element) doc.getElementsByTagName("medium").item(0);
            medElem.setAttribute("type", medium.getType());
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium's type set to " + medium.getType());

            Element nameElem = (Element) medElem.getElementsByTagName("name").item(0);
            nameElem.setTextContent(medium.getName());
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium's name set to " + medium.getName());

            // update movies

            Node moviesNode = medElem.getElementsByTagName("movies").item(0);
            medElem.removeChild(moviesNode);

            // movies
            Element moviesXml = doc.createElement("movies");

            // append movies to medium
            if (medium.getMovies() != null && medium.getMovies().size() != 0) {
                Iterator<Movie> iter = medium.getMovies().iterator();
                while (iter.hasNext()) {
                    Element movieXml = movieManager.createMovie(iter.next(), doc);
                    moviesXml.appendChild(movieXml);
                }
            }

            medElem.appendChild(moviesXml);

            // Upadte XML resource
            res.setContentAsDOM(doc);
            col.storeResource(res);


        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }


    }

    @Override
    public Set<Movie> getMediumsMovies(Medium medium) throws IllegalArgumentException, NullPointerException, DatabaseException {

        Set<Movie> movies = new HashSet<Movie>();
        if (medium == null) {
            throw new NullPointerException("movie is null!");
        }
        if (medium.getId() == null) {
            throw new IllegalArgumentException("Movie's ID is null!");
        }

        Collection col = null;
        XMLResource res = null;
        Document doc;
        try {
            // Get collection
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }

            // Get resource
            res = (XMLResource) col.getResource(medium.getId());
            if (res == null) {
                return null;
            }

            // Get DOM
            doc = (Document) res.getContentAsDOM();

            NodeList moviesNodes = doc.getElementsByTagName("movie");
            for (int i = 0; i < moviesNodes.getLength(); i++) {

                Movie newMovie = new Movie();

                NodeList params = moviesNodes.item(i).getChildNodes();
                for (int j = 0; j < params.getLength(); j++) {
                    Node item = params.item(j);

                    if (item instanceof Element) {
                        switch (item.getNodeName().toCharArray()[0]) {
                            case 't':
                                newMovie.setTitle(item.getTextContent());
                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's title set to [" + newMovie.getTitle() + "]");
                                break;
                            case 'n':
                                newMovie.setNote(item.getTextContent());
                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's note set to [" + newMovie.getNote() + "]");
                                break;
                            case 'g':
                                newMovie.setGenre(item.getTextContent());
                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's genre set to [" + newMovie.getGenre() + "]");
                                break;
                            case 'f':
                                newMovie.setFormat(item.getTextContent());
                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's format set to [" + newMovie.getFormat() + "]");
                                break;
                            case 'l':
                                if (item.getNodeName().compareTo("length") == 0) {
                                    newMovie.setLength(item.getTextContent());
                                    Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's length set to [" + newMovie.getLength() + "]");
                                    break;
                                } else {
                                    List<String> movieLang = new ArrayList<String>();
                                    NodeList languages = item.getChildNodes();
                                    for (int k = 0; k < languages.getLength(); k++) {
                                        Node lang = languages.item(k);
                                        if (lang instanceof Element) {
                                            if (lang.getNodeName().toCharArray()[0] == 'l') {
                                                movieLang.add(lang.getTextContent());
                                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's language added [" + lang.getTextContent() + "]");
                                            }
                                        }
                                    }
                                    newMovie.setLanguages(movieLang);
                                    break;
                                }

                            default:
                                break;
                        }
                    }
                }
                movies.add(newMovie);
            }

            return movies;


        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
    }

    @Override
    public List<String> getAllMediumsIds() throws DatabaseException {
        Collection col = null;
        try {
            col = getCollection();
            if (col == null) {
                throw new DatabaseException("Can't get collection from database!");
            }

            List<String> ids = new ArrayList(Arrays.asList(col.listResources()));
            if (ids.size() == 0) {
                return null;
            } else {
                return ids;
            }

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException(ex);
        } catch (DatabaseException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException(ex);
        } finally {
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }

    }

    @Override
    public void appendMovie(Medium medium, Movie movie) throws DatabaseException {
        if (medium == null || movie == null) {
            throw new NullPointerException("AppendMovie > medium or movie is null");
        }

        Collection col = null;
        XMLResource res = null;
        Document doc;

        try {
            // Get collection
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }

            // Get resource
            res = (XMLResource) col.getResource(medium.getId());
            if (res == null) {
                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + medium.getId() + " not found !!!");
                throw new DatabaseException("AppendMovie > Get resource with id failed :" + medium.getId());
            }

            //Check if medium doesn't contain Movie with the same title
            String xPath = String.format("/medium[@id='%s']//movie[title='%s']", medium.getId(), movie.getTitle());

            XPathQueryService service = (XPathQueryService) col.getService("XPathQueryService", "1.0");
            ResourceSet resultSet = service.query(xPath);
            if (resultSet.getSize() > 0) {
                throw new IllegalArgumentException("Movie with this title is already in medium :" + movie);
            }


            // Get DOM
            doc = (Document) res.getContentAsDOM();

            // update movies
            Element medElem = (Element) doc.getElementsByTagName("medium").item(0);
            Node moviesNode = doc.getElementsByTagName("movies").item(0);

            Element movieElem = movieManager.createMovie(movie, doc);
            moviesNode.appendChild(movieElem);

            medElem.replaceChild(moviesNode, moviesNode);

            // Upadte XML resource
            res.setContentAsDOM(doc);
            col.storeResource(res);


        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }


    }

    @Override
    public void removeMovie(Medium medium, Movie movie) throws DatabaseException, IllegalArgumentException {
        if (medium == null || movie == null) {
            throw new NullPointerException("AppendMovie > medium or movie is null");
        }

        Collection col = null;
        XMLResource res = null;
        Document doc;

        try {
            // Get collection
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }

            // Get resource
            res = (XMLResource) col.getResource(medium.getId());
            if (res == null) {
                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + medium.getId() + " not found !!!");
                throw new IllegalArgumentException("Movie not found in medium:" + movie);
            }
            // Get DOM
            doc = (Document) res.getContentAsDOM();
            Element medElem = (Element) doc.getElementsByTagName("medium").item(0);
            Node moviesNode = doc.getElementsByTagName("movies").item(0);

            //remove movie
            NodeList titleNodes = doc.getElementsByTagName("title");

            // Find movie XPATH = get over All mediums in collection => not effective, I use DOM .... 
            Node titleNode;
            Node removeNode = null;
            int i = 0;
            while (removeNode == null || i < titleNodes.getLength()) {
                titleNode = titleNodes.item(i);
                if (titleNode.getTextContent().compareTo(movie.getTitle()) == 0) {
                    removeNode = titleNode.getParentNode();
                }
                i++;
            }
            if (removeNode == null) {
                throw new IllegalArgumentException("Movie is not in Medium's movies in database: " + medium.getId() + "> " + movie);
            }

            moviesNode.removeChild(removeNode);
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie removed from medium:" + movie);

            medElem.replaceChild(moviesNode, moviesNode);

            // Upadte XML resource
            res.setContentAsDOM(doc);
            col.storeResource(res);

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
    }

    /**
     * return null, if medium is not in database *
     */
    @Override
    public Medium getMediumById(String id) throws NullPointerException, DatabaseException, IllegalArgumentException {
        Medium resultMedium;
        Collection col = null;
        XMLResource res = null;

        try {
            if (id == null || id.length() == 0) {
                throw new NullPointerException("Id si null");
            }

            // get collection 
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }
            //---------------------------------------------------------------------------------------------

            res = (XMLResource) col.getResource(id);
            if (res == null) {
                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + id + " not found !!!");
                return null;
            }
            /**
             * only for testing *
             */
            /*
             * String resultString = res.getContent().toString(); 
            System.out.println(resultString);
             */
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + id + " found");

            // Get medium as DOM Document
            Document medDoc = (Document) res.getContentAsDOM();
            if (medDoc == null) {
                throw new NullPointerException("Dom Node is null !!");
            }

            Node medNode = medDoc.getFirstChild();
            // Get medium from database
            resultMedium = new Medium();
            NodeList list = medNode.getChildNodes();

            // get id
            resultMedium.setId(id);
            // get Type
            resultMedium.setType(medNode.getAttributes().item(1).getNodeValue());
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium's type set to [" + resultMedium.getType() + "]");

            // get Name
            resultMedium.setName(list.item(1).getTextContent());
            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium's name set to [" + resultMedium.getName() + "]");

            // get movies
            Set<Movie> moviesRes = new HashSet<Movie>();
            NodeList movies = medDoc.getElementsByTagName("movie");

            for (int i = 0; i < movies.getLength(); i++) {
                // get movie
                Movie movie = new Movie();
                List<String> movieLang;
                NodeList movieAttr = movies.item(i).getChildNodes();
                for (int j = 0; j < movieAttr.getLength(); j++) {
                    Node item = movieAttr.item(j);

                    switch (item.getNodeName().toCharArray()[0]) {
                        case 't':
                            movie.setTitle(item.getTextContent());
                            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's title set to [" + movie.getTitle() + "]");
                            break;
                        case 'n':
                            movie.setNote(item.getTextContent());
                            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's note set to [" + movie.getNote() + "]");
                            break;
                        case 'g':
                            movie.setGenre(item.getTextContent());
                            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's genre set to [" + movie.getGenre() + "]");
                            break;
                        case 'f':
                            movie.setFormat(item.getTextContent());
                            Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's format set to [" + movie.getFormat() + "]");
                            break;
                        case 'l':
                            if (item.getNodeName().compareTo("length") == 0) {
                                movie.setLength(item.getTextContent());
                                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's length set to [" + movie.getLength() + "]");
                                break;
                            } else {
                                movieLang = new ArrayList<String>();
                                NodeList languages = item.getChildNodes();
                                Node lang = languages.item(1);
                                while (lang != null) {
                                    if (lang.getNodeName().toCharArray()[0] == 'l') {
                                        movieLang.add(lang.getTextContent());
                                        Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Movie's language added [" + lang.getTextContent() + "]");
                                    }
                                    lang = lang.getNextSibling();
                                }
                                movie.setLanguages(movieLang);
                                break;
                            }

                        default:
                            break;
                    }
                }
                moviesRes.add(movie);

            }
            resultMedium.setMovies(moviesRes);

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException("Restoring documents id's error!");

        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
        return resultMedium;
    }

    public Set<String> getMediumsWithMovie(String title) throws DatabaseException, IllegalArgumentException, NullPointerException {

        if (title == null || title.length() == 0) {
            throw new NullPointerException("title is null");
        }

        Set<String> ids = new HashSet<String>();
        Collection col = null;

        try {
            col = getCollection();
            if (col == null) {
                throw new NullPointerException("Can's get collection from database!");
            }

            // Get string from xPath => xPATH 2.0 demanded
            String xPath = String.format("//movie[title='%s']/../../@id/string()", title);

            XPathQueryService service = (XPathQueryService) col.getService("XPathQueryService", "1.0");
            ResourceSet resultSet = service.query(xPath);

            // movie with this title is not in database
            if (resultSet.getSize() == 0) {
                return null;
            }

            ResourceIterator results = resultSet.getIterator();
            while (results.hasMoreResources()) {
                Resource resource = results.nextResource();
                String result = (String) resource.getContent();
                ids.add(result);
            }
            return ids;

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException(ex);
        } finally {
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
    }

    @Override
    public Document getMediumAsDom(String id) throws DatabaseException {
        Collection col = null;
        Document medDoc = null;

        XMLResource res = null;

        try {
            if (id == null || id.length() == 0) {
                throw new NullPointerException("Id si null");
            }

            // get collection 
            col = this.getCollection();
            if (col == null) {
                throw new NullPointerException("Collection");
            }
            //---------------------------------------------------------------------------------------------

            res = (XMLResource) col.getResource(id);
            if (res == null) {
                Logger.getLogger(MediumManager.class.getName()).log(Level.SEVERE, "Medium with id " + id + " not found !!!");
                return null;
            }

            medDoc = (Document) res.getContentAsDOM();
        } catch (Exception ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException(ex);
        } finally {
            if (res != null) {
                try {
                    ((EXistResource) res).freeResources();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
        return medDoc;


    }
    
    @Override
    public Document getAllMoviesbyTitle(String title) throws DatabaseException{
          if (title == null || title.length() == 0) {
            throw new NullPointerException("title is null");
        }

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = null;
        try {
            docBuilder = docFactory.newDocumentBuilder();
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        Document movieDoc = docBuilder.newDocument();
        
        Collection col = null;

        try {
            col = getCollection();
            if (col == null) {
                throw new NullPointerException("Can's get collection from database!");
            }

            // Get string from xPath => xPATH 2.0 demanded
            String xPath = String.format("//movie[title='%s']", title);

            XPathQueryService service = (XPathQueryService) col.getService("XPathQueryService", "1.0");
            ResourceSet resultSet = service.query(xPath);

            // movie with this title is not in database
            if (resultSet.getSize() == 0) {
                return null;
            }
            
            Element movies = movieDoc.createElement("movies");

            ResourceIterator results = resultSet.getIterator();
            while (results.hasMoreResources()) {
                XMLResource resource = (XMLResource) results.nextResource();
                Element movie = (Element) resource.getContentAsDOM();
                movie.setAttribute("med_id", resource.getDocumentId());
                movies.appendChild(movie);
            }
            
            movieDoc.appendChild(movies);

        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException(ex);
        } finally {
            if (col != null) {
                try {
                    col.close();
                } catch (XMLDBException xe) {
                    xe.printStackTrace();
                }
            }
        }
        
        return movieDoc;
    }

    public String transformToString(DOMSource domSource, boolean isMovie) {
        InputStream is = null;
        try {
            URL url = null;
            if(isMovie){
                url = new URL(xsltPathMovies);                           
            }
            else {
                url = new URL(xsltPath);                
            }
            
            
            is = url.openStream();
            final StreamSource styleSource = new StreamSource(is);
            TransformerFactory tf = TransformerFactory.newInstance();
            Templates templates = tf.newTemplates(styleSource);
            Transformer transformer = templates.newTransformer();
            StringWriter sw = new StringWriter();
            StreamResult sr = new StreamResult(sw);
            transformer.transform(domSource, sr);
            return sw.toString();
        } catch (TransformerException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            return "Error with XML DB has been reached.";
        } catch (IOException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            return "Error with XML DB has been reached.";
        } finally {
            try {
                is.close();
            } catch (IOException ex) {
                Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
                return "Error with XML DB has been reached.";
            }
        }
    }

    /**
     * get collection from database *
     */
    private Collection getCollection() throws DatabaseException {
        Collection col = null;
        try {
            col = DatabaseManager.getCollection(URI + collectionName, admin, password);
        } catch (XMLDBException ex) {
            Logger.getLogger(MediumManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DatabaseException("getMediumById > Get collection failed :" + ex);
        }
        return col;
    }
}
